Release 10.1A: OpenEdge Development:
Progress Dynamics Basic Development


Client-side data validation

This section discusses the standard validation procedures to run on the client, without a database connection.

Column validation

For each field in the RowObject record of an SDO, you can optionally provide a validation procedure. Such procedures are named <column>Validate, where <column> is the name of the field in the RowObject record.

The action of a <column>Validate procedure should be to determine the validity of its input parameter (the same data type as the corresponding column in RowObject). On successful validation the procedure should RETURN. On unsuccessful validation the procedure should RETURN stringExpression. The string expression is added to a list of error messages for later presentation to the user.

Under no circumstances should a <column>Validate procedure RETURN ERROR. These procedures are run NO-ERROR for every column with a modified value, and the setting of the error condition is presumed to mean that no corresponding validation is defined. If your <column>Validate procedure returns an ERROR, then its validation is ignored.

Here is a simple example of a column validation procedure for the Customer.Name field:

PROCEDURE nameValidate: 
  DEFINE INPUT PARAMETER pcValue AS CHARACTER. 
  IF LENGTH(pcValue) < 2  
THEN RETURN "Name must be longer than 2 characters.".  
END PROCEDURE. 

Although the RETURN value can be a simple string as in this example, you should generally define messages for every type of message that can occur in the application so that these messages can be stored in the Repository and translated into other languages. The message utilities are discussed in the "Message handling in Progress Dynamics" section.

You can control, on a column-by-column basis, whether or not the validation is to occur on the client. If the <column>Validate procedure contains no database references (and this is indeed usually the case), then you can unselect the DB-REQUIRED flag in the AppBuilder code section editor. Doing so causes that procedure to be compiled into the SDO client proxy sdoname_cl.w (or its associated logic procedure proxy) and executed on the client.

Checking DB-REQUIRED on prevents the procedure from becoming part of the client proxy. Generally, any validation that requires the database connection should be placed into one of the pretransaction procedures discussed in the "Server-side validation" section. The advantage of using client-side logic at all is that validation not requiring a database access can be done without an AppServer call. In the event of an error, Progress Dynamics can return a message to the user without ever sending the update to the server.

All <column>Validate procedures, whether DB-REQUIRED is true or false, are compiled into the server-side portion of the SDO (<sdoname>.w or its associated logic procedure).

The fact that <column>Validate procedures are defined does not mean that these will be executed on the server, even though they are compiled into the server-side portion of the SDO. The server functions only perform <column>Validate (and rowObjectValidate—see later) if the attribute ServerSubmitValidation is set to TRUE.

In Progress Dynamics, <column>Validate and rowObjectValidate procedures (discussed below) are always executed on the server, unless one of the validation checks has already failed on the client and returned a message to the user. Note that although this might at first appear to be an extra overhead, it is fundamental to ensure that all validation fires correctly for non-Progress (for example, Java™) clients.

By default, <column>Validate procedures have access to only one piece of data—the value of the column in question. Although it is possible to gain access to other data through the direct access of the RowObject buffer, this is not recommended.

You should use <column>Validate when a column can be validated in isolation from other columns in the SDO. If the validation can be performed without reference to database objects, then this is an ideal candidate for column validation with DB-REQUIRED unchecked. (For example, verifying that a mandatory field has a value or that simple range criteria are observed.) Such validation will execute on the client without involving any AppServer requests should the validation fail. In particular, it can be useful to create such a procedure to validate an individual column when you anticipate that other client-side objects will want to execute that validation separately from validating the record as a whole. For example, if it is essential that validation be done on LEAVE of the field in a SmartDataViewer, without waiting until the rest of the update is done, then the viewer code can easily invoke the right <column>Validate procedure in its Data-Source without executing anything else.

Do not use <column>Validate if the validation must be performed on every record write. These procedures are only executed if the value of that particular column has been changed during the course of updating the record, or if the value has been changed from its default initial value in the case of an add or copy.

Additionally, avoid <column>Validate if the validation logic must consider the current settings of other fields—rowObjectValidate would be a better choice in this case.

Finally, be aware that <column>Validate executes prior to the commencement of a transaction. And always remember that the <column>Validate procedure will be compiled into the client-side object only if it involves no database access and DB-Required has been unchecked. Use preTransactionValidate and other server-side procedures to do other checks that occur before the transaction begins but that need access to the database.

rowObjectValidate

The rowObjectValidate procedure is intended for validation that must consider more than one field in the RowObject record.

If the rowObjectValidate procedure is defined and has DB-REQUIRED checked off, then it fires on the client after any client-side <column>Validate procedures have completed. Note that rowObjectValidate executes even if one or more of the <column>Validate procedures have failed and returned a validation message. Thus, all client-side validation is completed before the full list of errors is returned to the user. The following code is an example:

PROCEDURE rowObjectValidate: 
  IF RowObject.Balance > RowObject.CreditLimit THEN 
    RETURN "Balance may not exceed credit limit of " +  
      STRING(RowObject.CreditLimit). 
END PROCEDURE. 

All of the validation procedures should return an error message to signal error. Progress Dynamics supports a mechanism for returning a list of information about the error, including the table and field name, as well as a group and error ode (error number) for each error, using the include file aferrortxt.i. This include file and other message-handling files are described in the "Message handling in Progress Dynamics" section.

If rowObjectValidate is defined with DB-REQUIRED unchecked, then it will execute on the client. If DB-REQUIRED is checked on, then it will not execute on the client.

As with the validation procedures for individual columns, you should avoid DB-REQUIRED code for rowObjectValidate. The intention here is that as much of your validation should execute client-side as possible to reduce AppServer traffic. Move validation that might cause rowObjectValidate to require a database connection to preTransactionValidate so that it executes on the server-side.

Use rowObjectValidate whenever your validation logic can be performed without any database access, and prior to the start of a database transaction, but requires access to more than one column value in the SDO.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095